#include "Mensaje.h"
#include <netdb.h>
#include <cstring>
#include <string>

Mensaje::Mensaje() {
    this->limpiar();
}

Mensaje::~Mensaje() {
}

void Mensaje::limpiar() {
    this->data.clear();
    this->firma = "";
    this->key = "";
}

bool Mensaje::hidratar(std::string msg_serial) {
    t_long_msg long_mensaje;
    std::string json_string;
    Json::Reader reader;

    memcpy(&long_mensaje, msg_serial.data(), sizeof(t_long_msg));
    long_mensaje = ntohl(long_mensaje);
    this->firma.assign(msg_serial.data() + sizeof(t_long_msg), LONG_FIRMA);
    json_string.assign(msg_serial.data() + sizeof(t_long_msg) + LONG_FIRMA,
                       long_mensaje);

    bool parsingSuccessful = reader.parse(json_string, this->getData());

    return parsingSuccessful;
}

bool Mensaje::hidratar(char *msg_serial) {
    t_long_msg long_mensaje;
    std::string json_string;
    Json::Reader reader;

    memcpy(&long_mensaje, msg_serial, sizeof(t_long_msg));
    long_mensaje = ntohl(long_mensaje);
    this->firma.assign(msg_serial + sizeof(t_long_msg), LONG_FIRMA);
    json_string.assign(msg_serial + sizeof(t_long_msg) + LONG_FIRMA,
                       long_mensaje);

    bool parsingSuccessful = reader.parse(json_string, this->getData());

    return parsingSuccessful;
}

std::string Mensaje::serializar() {
    t_long_msg long_mensaje, long_mensaje_big_endian;
    Json::StyledWriter writer;
    std::string json_string;
    std::string mensaje_serializado;

    json_string = writer.write(getData());
    long_mensaje = json_string.length();
    int tamanio_total_serializado = sizeof(t_long_msg) + 
                                           LONG_FIRMA + long_mensaje;

    long_mensaje_big_endian = htonl(long_mensaje);

    char *buffer = new char[tamanio_total_serializado];
    // Campo 1: long. del json
    memcpy(buffer, &long_mensaje_big_endian, sizeof(t_long_msg));
    // Campo 2: firma del mensaje
    memcpy(buffer + sizeof(t_long_msg), generarFirma().c_str(), LONG_FIRMA);
    // Campo 3: json en string
    memcpy(buffer + sizeof(t_long_msg) + LONG_FIRMA, json_string.c_str(),
           long_mensaje);

    mensaje_serializado.assign(buffer, tamanio_total_serializado);
    delete[] buffer;
    return mensaje_serializado;
}

std::string Mensaje::generarFirma() {
    if (this->key == "") {
        std::string firma_nula(LONG_FIRMA, '0');
        return firma_nula;
    }
    return firmador.generarFirma(this->getJsonString(), this->key);
}

std::string Mensaje::getJsonString() {
    Json::StyledWriter writer;
    return writer.write(this->getData());
}

void Mensaje::imprimir() {
    std::cout << "Key: " << this->getKey()
              << std::endl << "Json: "
              << std::endl << this->getData()
              << std::endl << "Firma HMAC: "
              << this->firma << std::endl;
}

std::string Mensaje::aString() {
    std::stringstream ss;
    ss << "Key: " << this->getKey()
              << std::endl << "Json: "
              << std::endl << this->getData()
              << std::endl << "Firma HMAC: "
              << this->firma << std::endl;
return ss.str();
}
